package com.suntianci.stock.sharding;

import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.joda.time.DateTime;

import java.util.Collection;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.Date;

/**
 * @ClassName CommonShardingAlgorithm4Db
 * @Author 孙天赐
 * @Date 2025/2/24 9:57
 * @Description TODO:定义公共的数据库分片算法类：包含精准匹配数据库和范围匹配数据库
 * *                因为分库是根据日期分库的，一年一个库，所以片键的类型是Date
 */
public class CommonShardingAlgorithm4Db implements PreciseShardingAlgorithm<Date>, RangeShardingAlgorithm<Date> {

    /**
     * TODO 精准匹配数据库的方法 cur_time 条件必须是 = 或者 in
     *
     * @param dsNames       所有可匹配数据源的集合 ds-2025 ...
     * @param shardingValue
     * @return
     */
    @Override
    public String doSharding(Collection<String> dsNames, PreciseShardingValue<Date> shardingValue) {
        // 1.思路：根据传入的日期值，获取年份字符串
        // 获取分片字段的名称colume
//        String columnName = shardingValue.getColumnName();
        // 获取逻辑表名称
//        String logicTableName = shardingValue.getLogicTableName();
        // 获取分片值（查询的条件值）
        Date value = shardingValue.getValue();
        // 获取年份字符串
        String year = new DateTime(value).getYear() + "";
        // 2.从ds集合中过滤出以指定年份结尾的数据源
        Optional<String> optional = dsNames.stream().filter(ds -> ds.endsWith(year)).findFirst();
        // 如果有结果，则返回
        if (optional.isPresent()) {
            return optional.get();
        }
        return null;
    }

    /**
     * TODO 范围查询匹配数据源 关键字：between and
     *
     * @param dsNames       所有可匹配数据源的集合 ds-2025 ...
     * @param shardingValue
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> dsNames, RangeShardingValue<Date> shardingValue) {
        // 获取分片字段名称
//        String columnName = shardingValue.getColumnName();
//      // 获取逻辑表名称
//        String logicTableName = shardingValue.getLogicTableName();
        // 1.获取范围封装对象
        Range<Date> valueRange = shardingValue.getValueRange();
        // 2.1 判断条件是否有下限值
        if (valueRange.hasLowerBound()) {
            // 获取条件下限日期
            Date lowerDate = valueRange.lowerEndpoint();
            // 获取条件所属年份  dsNames--> ds_2025 ...
            int year = new DateTime(lowerDate).getYear();
            // 过滤出数据源中年份大于等于lowerDate的数据源
            dsNames = dsNames.stream().filter(dsName -> Integer.valueOf(dsName.substring(dsName.lastIndexOf("-") + 1)) >= year)
                    .collect(Collectors.toList());
        }
        // 2.2 判断条件是否有上限值
        if (valueRange.hasUpperBound()) {
            // 获取条件上限日期
            Date upperDate = valueRange.upperEndpoint();
            // 获取条件所属年份
            int year = new DateTime(upperDate).getYear();
            // 过滤出数据源中年份小于等于upperDate的数据源
            dsNames = dsNames.stream().filter(dsName -> Integer.valueOf(dsName.substring(dsName.lastIndexOf("-") + 1)) <= year)
                    .collect(Collectors.toList());
        }

        return dsNames;
    }
}
